home *** CD-ROM | disk | FTP | other *** search
- /* Output GDB-format symbol table information from GNU compiler.
- Copyright (C) 1987, 1988 Free Software Foundation, Inc.
-
- This file is part of GNU CC.
-
- GNU CC is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 1, or (at your option)
- any later version.
-
- GNU CC is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNU CC; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-
- #include "config.h"
- #include "tree.h"
- #include "symseg.h"
- #include "rtl.h"
- #include "gdbfiles.h"
- #include <stdio.h>
- #undef NULL
- /* <...> used here so one can prevent use of ./stddef.h
- by changing the -I options used. */
- #include <stddef.h>
-
- /* Get N_SO from stab.h if we can expect the file to exist. */
- #ifdef DBX_DEBUGGING_INFO
- #ifdef USG
- #include "stab.h" /* If doing DBX on sysV, use our own stab.h. */
- #else
- #include <stab.h> /* On BSD, use the system's stab.h. */
- #endif /* not USG */
- #endif
-
- /* .stabs code for source file name. */
- #ifndef N_SO
- #define N_SO 0x64
- #endif
-
- /* Unix maximum on file name length. Needed for getwd. */
- #define MAXNAMLEN 1024
-
- /* Get the number to output for a reference to type TYPE. */
- #define TYPE_OUTPUT_ADDRESS(TYPE) \
- TYPE_SYMTAB_ADDRESS (TYPE_MAIN_VARIANT (TYPE))
-
- /* Stream for writing symbol table file. */
- static FILE *symfile;
-
- /* Name of symbol table file. */
- static char *symfile_name;
-
- /* Stream for writing to assembler file. */
- static FILE *asmfile;
-
- /* Address for allocating space in symbol table file.
- Changes in this variable are paired globally with writes to symfile,
- but often we allocate many structures, advancing next_address,
- before writing any of them. */
- static int next_address;
-
- /* Chain recording all the types that have been output,
- giving the address-in-the-symseg of each one. */
-
- struct typevec_elt
- {
- int address;
- struct typevec_elt *next;
- };
-
- static struct typevec_elt *typevec;
-
- /* Number of types recorded so far in the chain. */
-
- static int total_types;
-
- /* Lists of types to which forward references have been made.
- Separate lists for temporary and permanent types. */
-
- static tree temporary_fwd_refs;
- static tree permanent_fwd_refs;
-
- /* `blockvec' is a chain recording all the symbol-blocks that have been output,
- giving the address-in-the-symseg of each one. */
-
- struct blockvec_elt
- {
- int address;
- struct blockvec_elt *next;
- };
-
- static struct blockvec_elt *blockvec;
-
- /* Number of blocks recorded so far in the chain. */
-
- static int total_blocks;
-
- static void symout_range_bounds ();
- static void symout_array_domain ();
- static void symout_record_fields ();
- static void symout_enum_values ();
- static void symout_record_field_names ();
- static void symout_enum_value_names ();
- static int subrange_p ();
- static void symout_strings_skip ();
- static void symout_strings_print ();
-
- /* At the beginning of compilation, start writing the symbol table.
- Initialize the type and block chain.
- Also open and initialize the symseg file. */
-
- void
- symout_init (filename, asm_file, sourcename)
- char *filename;
- FILE *asm_file;
- char *sourcename;
- {
- struct symbol_root buffer;
-
- #ifdef VMS
- fatal ("Cannot write GDB debugging format on VMS");
- #endif
-
- asmfile = asm_file;
- fprintf (asmfile, ".text 0\n.gdbbeg 0\n.gdbbeg 1\n");
- fprintf (asmfile,
- "Ltext:\t.stabs \"%s\",%d,0,0,Ltext\n",
- sourcename, N_SO);
- fprintf (asmfile, ".data 0\nLdata:\n");
- ASM_OUTPUT_LOCAL (asmfile, "Lbss", 0, 0);
- fprintf (asmfile, ".gdbsym Ldata,%d\n",
- (char *) &buffer.databeg - (char *) &buffer);
- fprintf (asmfile, ".gdbsym Lbss,%d\n",
- (char *) &buffer.bssbeg - (char *) &buffer);
-
- symfile = fopen (filename, "w");
- if (symfile == 0)
- pfatal_with_name (filename);
- symfile_name = (char *) malloc (strlen (filename) + 1);
- strcpy (symfile_name, filename);
-
- typevec = 0;
- blockvec = 0;
- total_types = 0;
- total_blocks = 0;
-
- permanent_fwd_refs = 0;
- temporary_fwd_refs = 0;
-
- bzero (&buffer, sizeof buffer);
- fwrite (&buffer, sizeof buffer, 1, symfile);
-
- next_address = sizeof buffer;
- }
-
- /* Functions for outputting strings into the symbol table.
- The string to be output is effectively the concatenation of
- the two strings P1 and P2. Their lengths are given as S1 and S2.
- If P1 or P2 is zero, that string is not used.
-
- A null character is output to terminate the string,
- and it is followed by more nulls as padding to a word boundary. */
-
- static void
- symout_strings (p1, s1, p2, s2)
- char *p1;
- int s1;
- char *p2;
- int s2;
- {
- symout_strings_print (p1, s1, p2, s2);
- symout_strings_skip (p1, s1, p2, s2);
- }
-
- /* Like symout_strings but only output; do not update next_address. */
-
- static void
- symout_strings_print (p1, s1, p2, s2)
- char *p1;
- int s1;
- char *p2;
- int s2;
- {
- register int total;
-
- if (p1 && s1 == 0)
- s1 = strlen (p1);
- if (p2 && s2 == 0)
- s2 = strlen (p2);
-
- if (p1)
- fwrite (p1, s1, 1, symfile);
- if (p2)
- fwrite (p2, s2, 1, symfile);
- putc (0, symfile);
-
- total = s1 + s2 + 1;
- while (total % sizeof (int))
- {
- putc (0, symfile);
- total++;
- }
- }
-
- /* Like symout_strings but just update next_address; do not output. */
-
- static void
- symout_strings_skip (p1, s1, p2, s2)
- char *p1;
- int s1;
- char *p2;
- int s2;
- {
- register int total;
-
- if (p1 && s1 == 0)
- s1 = strlen (p1);
- if (p2 && s2 == 0)
- s2 = strlen (p2);
-
- total = s1 + s2 + 1;
- while (total % sizeof (int))
- total++;
-
- next_address += total;
- }
-
- /* Call here to output a chain of types.
- After each function, this is done first for the chain of permanent types
- made during the function, and then for the chain of temporary types.
- This must be done before outputting the symbols and blocks of the function.
-
- At the end of compilation, this is done for all the permanent types
- made since the last function.
-
- Each permanent type is done once, at the beginning of the next function,
- or at the end of the compilation if no functions follow.
- Once a type has been processed here, its TYPE_SYMTAB_ADDRESS remains
- set up. */
-
- void
- symout_types (types)
- tree types;
- {
- struct typerec
- {
- int number;
- int address;
- int nfields;
- int fields_address;
- int name_address;
- char *name;
- char *name_prefix;
- };
-
- register int n_types, i;
- register struct typerec *records;
- register tree next;
- struct type buffer;
- int this_run_address = next_address;
-
- /* Count the number of types to be handled here. */
-
- for (next = types, n_types = 0;
- next;
- next = TREE_CHAIN (next), n_types++);
-
- records = (struct typerec *) alloca (n_types * sizeof (struct typerec));
-
- /* Compute the amount of space each type needs, updating next_address
- and storing the address of the data for each type. */
-
- for (next = types, i = 0;
- next;
- next = TREE_CHAIN (next), i++)
- {
- register struct typevec_elt *velt
- = (struct typevec_elt *) xmalloc (sizeof (struct typevec_elt));
- velt->next = typevec;
- typevec = velt;
-
- total_types++;
-
- if (TYPE_NAME (next))
- {
- records[i].name_address = next_address;
-
- if (TREE_CODE (TYPE_NAME (next)) == IDENTIFIER_NODE)
- {
- records[i].name = IDENTIFIER_POINTER (TYPE_NAME (next));
- switch (TREE_CODE (next))
- {
- case RECORD_TYPE:
- records[i].name_prefix = "struct ";
- break;
-
- case UNION_TYPE:
- records[i].name_prefix = "union ";
- break;
-
- case ENUMERAL_TYPE:
- records[i].name_prefix = "enum ";
- break;
- }
- }
- else
- {
- records[i].name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (next)));
- records[i].name_prefix = 0;
- }
- symout_strings_skip (records[i].name_prefix, 0,
- records[i].name, 0);
-
- }
- else
- {
- records[i].name = 0;
- records[i].name_address = 0;
- records[i].name_prefix = 0;
- }
-
- /* If this type was forward-referenced from a previous call
- to symout_types, store this type's address into the reference. */
- if (TYPE_POINTER_TO (next) != 0
- && TYPE_SYMTAB_ADDRESS (TYPE_POINTER_TO (next)) != 0
- && TYPE_SYMTAB_ADDRESS (TYPE_POINTER_TO (next)) < this_run_address)
- {
- int pos = ftell (symfile);
- int myaddr = next_address;
- fflush (symfile);
- fseek (symfile,
- (TYPE_SYMTAB_ADDRESS (TYPE_POINTER_TO (next))
- + offsetof (struct type, target_type)),
- 0);
- fwrite (&myaddr, sizeof (int), 1, symfile);
- fflush (symfile);
- fseek (symfile, pos, 0);
- }
-
- records[i].address = next_address;
- TYPE_SYMTAB_ADDRESS (next) = next_address;
- velt->address = next_address;
- next_address += sizeof (struct type);
- records[i].nfields = 0;
- records[i].fields_address = 0;
- switch (TREE_CODE (next))
- {
- case ARRAY_TYPE:
- records[i].nfields
- = (TYPE_DOMAIN(next)
- ? ! integer_zerop (TYPE_MIN_VALUE (TYPE_DOMAIN (next)))
- : 0 );
- break;
-
- case INTEGER_TYPE:
- if (subrange_p (next))
- buffer.nfields = 2;
- break;
-
- case RECORD_TYPE:
- case UNION_TYPE:
- case ENUMERAL_TYPE:
- records[i].nfields = list_length (TYPE_FIELDS (next));
- }
- if (records[i].nfields)
- records[i].fields_address = next_address;
- next_address += records[i].nfields * sizeof (struct field);
- }
-
- /* Now write the data whose space we have assigned.
- First fill the data into BUFFER, then write BUFFER. */
-
- for (next = types, i = 0;
- next;
- next = TREE_CHAIN (next), i++)
- {
- if (records[i].name)
- symout_strings_print (records[i].name_prefix, 0,
- records[i].name, 0);
-
- if (TREE_TYPE (next) != 0 && TYPE_OUTPUT_ADDRESS (TREE_TYPE (next)) == 0)
- {
- /* We are making a forward-reference to our target type.
- Make a list of all of these. */
- if (TREE_PERMANENT (next))
- permanent_fwd_refs
- = perm_tree_cons (TREE_TYPE (next), 0, permanent_fwd_refs);
- else
- temporary_fwd_refs
- = tree_cons (TREE_TYPE (next), 0, temporary_fwd_refs);
- }
-
- if (TYPE_SIZE (next) == 0)
- buffer.length = 0;
- else
- buffer.length
- = (TREE_INT_CST_LOW (TYPE_SIZE (next))
- * TYPE_SIZE_UNIT (next) / BITS_PER_UNIT);
-
- buffer.name = (char *) records[i].name_address;
- buffer.target_type = (struct type *) (TREE_TYPE (next) ? TYPE_OUTPUT_ADDRESS (TREE_TYPE (next)) : 0);
-
- buffer.pointer_type = 0;
- buffer.function_type = 0;
- buffer.flags
- = ((TREE_CODE (next) == INTEGER_TYPE || TREE_CODE (next) == ENUMERAL_TYPE)
- && TREE_UNSIGNED (next))
- ? TYPE_FLAG_UNSIGNED : 0;
- buffer.nfields = records[i].nfields;
- buffer.fields = (struct field *) records[i].fields_address;
-
- switch (TREE_CODE (next))
- {
- case INTEGER_TYPE:
- buffer.code = TYPE_CODE_INT;
- if (buffer.nfields)
- buffer.code = TYPE_CODE_RANGE;
- break;
-
- case REAL_TYPE:
- buffer.code = TYPE_CODE_FLT;
- break;
-
- case VOID_TYPE:
- buffer.code = TYPE_CODE_VOID;
- break;
-
- case POINTER_TYPE:
- buffer.code = TYPE_CODE_PTR;
- break;
-
- case ARRAY_TYPE:
- if (buffer.nfields == 0)
- buffer.code = TYPE_CODE_ARRAY;
- else
- buffer.code = TYPE_CODE_PASCAL_ARRAY;
- break;
-
- case RECORD_TYPE:
- buffer.code = TYPE_CODE_STRUCT;
- break;
-
- case UNION_TYPE:
- buffer.code = TYPE_CODE_UNION;
- break;
-
- case FUNCTION_TYPE:
- buffer.code = TYPE_CODE_FUNC;
- break;
-
- case ENUMERAL_TYPE:
- buffer.code = TYPE_CODE_ENUM;
- break;
-
- default:
- abort ();
- }
-
- fwrite (&buffer, sizeof buffer, 1, symfile);
-
- /* Now write the `struct field's that certain kinds of type have.
- This allocates space for the names of those fields,
- incrementing next_address for the names. */
-
- switch (TREE_CODE (next))
- {
- case ARRAY_TYPE:
- if (buffer.nfields)
- symout_array_domain (next);
- break;
-
- case RECORD_TYPE:
- case UNION_TYPE:
- symout_record_fields (next);
- break;
-
- case ENUMERAL_TYPE:
- symout_enum_values (next);
- break;
-
- case INTEGER_TYPE:
- if (buffer.nfields)
- symout_range_bounds (next);
- }
- }
-
- /* Now output the strings referred to by the fields of certain types.
- (next_address was already updated for these strings.) */
-
- for (next = types, i = 0;
- next;
- next = TREE_CHAIN (next), i++)
- {
- switch (TREE_CODE (next))
- {
- case RECORD_TYPE:
- case UNION_TYPE:
- symout_record_field_names (next);
- break;
-
- case ENUMERAL_TYPE:
- symout_enum_value_names (next);
- break;
- }
- }
- }
-
- /* Given a list of types TYPES, return a chain of just those
- that haven't been written in the symbol table. */
-
- static tree
- filter_undefined_types (types)
- tree types;
- {
- tree new = 0;
- tree next;
-
- for (next = types; next; next = TREE_CHAIN (next))
- if (TYPE_SYMTAB_ADDRESS (TREE_PURPOSE (next)) == 0)
- {
- TREE_CHAIN (TREE_PURPOSE (next)) = new;
- new = TREE_PURPOSE (next);
- }
-
- return new;
- }
-
- /* Return nonzero if TYPE's range of possible values
- is not the full range allowed by the number of bits it has.
- TYPE is assumed to be an INTEGER_TYPE or ENUMERAL_TYPE. */
-
- static int
- subrange_p (type)
- tree type;
- {
- int uns = TREE_UNSIGNED (type);
-
- if (TYPE_PRECISION (type) >= HOST_BITS_PER_INT)
- {
- if (uns)
- return integer_zerop (TYPE_MIN_VALUE (type))
- && TREE_INT_CST_LOW (TYPE_MAX_VALUE (type)) == 0
- && (TREE_INT_CST_HIGH (TYPE_MAX_VALUE (type))
- == (1 << (TYPE_PRECISION (type) - HOST_BITS_PER_INT)) - 1);
- return TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)) == 0
- && TREE_INT_CST_LOW (TYPE_MAX_VALUE (type)) == 0
- && (TREE_INT_CST_HIGH (TYPE_MIN_VALUE (type))
- == (-1) << (TYPE_PRECISION (type) - 1 - HOST_BITS_PER_INT))
- && (TREE_INT_CST_HIGH (TYPE_MAX_VALUE (type))
- == (1 << (TYPE_PRECISION (type) - 1 - HOST_BITS_PER_INT)) - 1);
- }
-
- if (uns)
- {
- int mask;
-
- if (TYPE_PRECISION (type) == HOST_BITS_PER_INT)
- /* Shifting by 32 loses on some machines. */
- mask = -1;
- else
- mask = (1 << TYPE_PRECISION (type)) - 1;
-
- return (integer_zerop (TYPE_MIN_VALUE (type))
- && (TREE_INT_CST_LOW (TYPE_MAX_VALUE (type)) == mask));
- }
- else
- return ((TREE_INT_CST_LOW (TYPE_MIN_VALUE (type))
- == (-1) << (TYPE_PRECISION (type) - 1))
- && (TREE_INT_CST_LOW (TYPE_MAX_VALUE (type))
- == (1 << (TYPE_PRECISION (type) - 1)) - 1));
- }
-
- /* Functions to output the "fields" of various kinds of types.
- These assume that next_address has already been incremented to
- cover these fields, and the fields of all the other types being
- output in this batch; so next_address can be used to allocate
- space to store field names, etc. */
-
- static void
- symout_array_domain (type)
- tree type;
- {
- struct field buffer;
-
- buffer.bitpos = 0;
- buffer.bitsize = 0;
- buffer.type = (struct type *) TYPE_OUTPUT_ADDRESS (TYPE_DOMAIN (type));
- buffer.name = 0;
- fwrite (&buffer, sizeof (struct field), 1, symfile);
- }
-
- static void
- symout_range_bounds (type)
- tree type;
- {
- struct field buffer;
-
- buffer.bitpos = TREE_INT_CST_LOW (TYPE_MIN_VALUE (type));
- buffer.bitsize = 0;
- buffer.type = (struct type *) TYPE_OUTPUT_ADDRESS (type);
- buffer.name = 0;
- fwrite (&buffer, sizeof (struct field), 1, symfile);
-
- buffer.bitpos = TREE_INT_CST_LOW (TYPE_MAX_VALUE (type));
- buffer.bitsize = 0;
- buffer.type = (struct type *) TYPE_OUTPUT_ADDRESS (type);
- buffer.name = 0;
- fwrite (&buffer, sizeof (struct field), 1, symfile);
- }
-
- static void
- symout_record_fields (type)
- tree type;
- {
- struct field buffer;
- register tree field;
-
- for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
- {
- buffer.bitpos = DECL_OFFSET (field);
- buffer.bitsize
- = (TREE_PACKED (field)
- ? TREE_INT_CST_LOW (DECL_SIZE (field)) * DECL_SIZE_UNIT (field)
- : 0);
- buffer.type = (struct type *) TYPE_OUTPUT_ADDRESS (TREE_TYPE (field));
- if (DECL_NAME (field))
- {
- buffer.name = (char *) next_address;
- symout_strings_skip (0, IDENTIFIER_LENGTH (DECL_NAME (field)), 0, 0);
- }
- else
- buffer.name = 0;
- fwrite (&buffer, sizeof (struct field), 1, symfile);
- }
- }
-
- static void
- symout_enum_values (type)
- tree type;
- {
- struct field buffer;
- register tree link, value;
-
- for (link = TYPE_VALUES (type); link; link = TREE_CHAIN (link))
- {
- value = TREE_VALUE (link);
- buffer.bitpos = TREE_INT_CST_LOW (value);
- buffer.bitsize = 0;
- buffer.type = (struct type *) TYPE_OUTPUT_ADDRESS (type);
- buffer.name = (char *) next_address;
- symout_strings_skip (0, IDENTIFIER_LENGTH (TREE_PURPOSE (link)), 0, 0);
- fwrite (&buffer, sizeof buffer, 1, symfile);
- }
- }
-
- /* Output field names or value names for the fields of a type.
- This is called, for the types that need it, after the fields
- have been output for all the types in the batch.
- We do not update next_address here, because it has already been
- updated for all the names in all the fields in all the types. */
-
- static void
- symout_record_field_names (type)
- tree type;
- {
- register tree field;
-
- for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
- if (DECL_NAME (field))
- symout_strings_print (IDENTIFIER_POINTER (DECL_NAME (field)),
- IDENTIFIER_LENGTH (DECL_NAME (field)),
- 0, 0);
- }
-
- static void
- symout_enum_value_names (type)
- tree type;
- {
- register tree value;
-
- for (value = TYPE_VALUES (type); value; value = TREE_CHAIN (value))
- symout_strings_print (IDENTIFIER_POINTER (TREE_PURPOSE (value)),
- IDENTIFIER_LENGTH (TREE_PURPOSE (value)),
- 0, 0);
- }
-
- /* Output the symbols of a block, given the list of decl nodes.
- Store the file addresses at which the symbols are output
- into ADDR_BUFFER, a vector which has just the right length.
-
- If FILTER is 1, do only the private symbols in DECLS.
- If FILTER is 2, do only the public ones (but no externals).
- If FILTER is 0, do all (except external functions). */
-
- static void
- symout_block_symbols (decls, addr_buffer, filter)
- tree decls;
- int *addr_buffer;
- int filter;
- {
- register tree decl;
- struct symbol buffer;
- register int i;
-
- for (decl = decls, i = 0; decl; decl = TREE_CHAIN (decl))
- {
- register int name_address = next_address;
-
- if (filter == (TREE_PUBLIC (decl) ? 1 : 2))
- continue;
-
- /* Do not mention external functions.
- Let their own files mention them.
- In the top blocks, don't mention external anything. */
-
- if (TREE_EXTERNAL (decl)
- && (filter || TREE_CODE (TREE_TYPE (decl)) == FUNCTION_TYPE))
- continue;
-
- if (TREE_TYPE (decl) == error_mark_node)
- continue;
-
- symout_strings (IDENTIFIER_POINTER (DECL_NAME (decl)),
- IDENTIFIER_LENGTH (DECL_NAME (decl)),
- 0, 0);
- addr_buffer[i] = next_address;
- buffer.name = (char *) name_address;
- buffer.namespace = VAR_NAMESPACE;
- buffer.type = (struct type *) TYPE_OUTPUT_ADDRESS (TREE_TYPE (decl));
- switch (TREE_CODE (decl))
- {
- case PARM_DECL:
- buffer.class = LOC_ARG;
- buffer.value.value = DECL_OFFSET (decl) / BITS_PER_UNIT;
- break;
-
- case VAR_DECL:
- case RESULT_DECL:
- if (TREE_STATIC (decl) || TREE_EXTERNAL (decl))
- {
- if (! TREE_PUBLIC (decl) || DECL_INITIAL (decl))
- {
- char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
- fprintf (asmfile, "\t.gdbsym ");
- ASM_OUTPUT_LABELREF (asmfile, str);
- fprintf (asmfile, ",%d\n",
- next_address + (char *)&buffer.value - (char *)&buffer);
- buffer.class = LOC_STATIC;
- }
- else
- /* Uninitialized public symbols are output as .comm;
- Tell GDB to get address from loader global symbol.
- Also come here for symbols declared extern. */
- buffer.class = LOC_EXTERNAL;
- }
- else
- {
- if (GET_CODE (DECL_RTL (decl)) == REG)
- {
- buffer.class = LOC_REGISTER;
- buffer.value.value = REGNO (DECL_RTL (decl));
- /* Detect vars that were optimized entirely away. */
- if (buffer.value.value == -1)
- buffer.class = LOC_CONST;
- }
- else if (GET_CODE (DECL_RTL (decl)) == MEM
- && (GET_CODE (XEXP (DECL_RTL (decl), 0)) == MEM
- || (GET_CODE (XEXP (DECL_RTL (decl), 0)) == REG
- && REGNO (XEXP (DECL_RTL (decl), 0)) != FRAME_POINTER_REGNUM)))
- /* If the value is indirect by memory or by a register
- that isn't the frame pointer
- then it means the object is variable-sized and address through
- that register or stack slot.
- If we have a pointer-type (which we should, for an array),
- output the variable as a pointer.
- Otherwise ignore it, since it is hard to create the ptr
- type now and output it, and -gg is being retired. */
- {
- tree ptype = TYPE_POINTER_TO (TREE_TYPE (TREE_TYPE (decl)));
- if (ptype == 0
- || TYPE_OUTPUT_ADDRESS (ptype) == 0)
- continue;
-
- buffer.type = (struct type *) TYPE_OUTPUT_ADDRESS (ptype);
-
-
- if (GET_CODE (XEXP (DECL_RTL (decl), 0)) == REG)
- {
- buffer.class = LOC_REGISTER;
- buffer.value.value = REGNO (DECL_RTL (decl));
- /* Detect vars that were optimized entirely away. */
- if (buffer.value.value == -1)
- buffer.class = LOC_CONST;
- }
- else
- {
- register rtx addr = XEXP (DECL_RTL (decl), 0);
- if (GET_CODE (addr) != PLUS && GET_CODE (addr) != MINUS)
- abort ();
- if (GET_CODE (XEXP (addr, 1)) != CONST_INT)
- abort ();
- buffer.class = LOC_LOCAL;
- buffer.value.value = INTVAL (XEXP (addr, 1));
- if (GET_CODE (addr) == MINUS)
- buffer.value.value = - buffer.value.value;
- }
- }
- /* Locals in memory are expected to be addressed as
- (PLUS (REG ...) (CONST_INT ...)).
- Bomb out if that is not so. */
- else if (GET_CODE (DECL_RTL (decl)) == MEM)
- {
- register rtx addr = XEXP (DECL_RTL (decl), 0);
- if (GET_CODE (addr) != PLUS && GET_CODE (addr) != MINUS)
- abort ();
- if (GET_CODE (XEXP (addr, 1)) != CONST_INT)
- abort ();
- buffer.class = LOC_LOCAL;
- buffer.value.value = INTVAL (XEXP (addr, 1));
- if (GET_CODE (addr) == MINUS)
- buffer.value.value = - buffer.value.value;
- }
- else
- abort ();
- }
- break;
-
- case TYPE_DECL:
- buffer.class = LOC_TYPEDEF;
- buffer.value.value = 0;
- break;
-
- case CONST_DECL:
- buffer.class = LOC_CONST;
- buffer.value.value = TREE_INT_CST_LOW (DECL_INITIAL (decl));
- break;
-
- case FUNCTION_DECL:
- if (DECL_INITIAL (decl))
- {
- buffer.class = LOC_BLOCK;
- buffer.value.value = DECL_BLOCK_SYMTAB_ADDRESS (decl);
- }
- else
- buffer.class = LOC_EXTERNAL;
- }
-
- fwrite (&buffer, sizeof buffer, 1, symfile);
- next_address += sizeof buffer;
- i++;
- }
- }
-
- /* Output the tags (struct, union and enum definitions) for a block,
- given a list of them (a chain of TREE_LIST nodes) in TAGS.
- Store their addresses in the file into ADDR_BUFFER. */
-
- static void
- symout_block_tags (tags, addr_buffer)
- tree tags;
- int *addr_buffer;
- {
- register tree tag;
- struct symbol buffer;
- register int i;
-
- for (tag = tags, i = 0; tag; tag = TREE_CHAIN (tag), i++)
- {
- buffer.name = (char *) next_address;
-
- symout_strings (IDENTIFIER_POINTER (TREE_PURPOSE (tag)),
- IDENTIFIER_LENGTH (TREE_PURPOSE (tag)),
- 0, 0);
- addr_buffer[i] = next_address;
- buffer.namespace = STRUCT_NAMESPACE;
- buffer.type = (struct type *) TYPE_OUTPUT_ADDRESS (TREE_VALUE (tag));
- buffer.class = LOC_TYPEDEF;
- buffer.value.value = 0;
-
- fwrite (&buffer, sizeof buffer, 1, symfile);
- next_address += sizeof buffer;
- }
- }
-
- /* Output all the data structure for a "block"
- (any binding contour).
- DECLS is the chain of declarations of variables in this block.
- TAGS is the list of struct, union and enum tag definitions of this block.
- SUPERBLOCK_ADDRESS is the symtab file address of the containing block's
- data structure. */
-
- int
- symout_block (decls, tags, args, superblock_address)
- tree decls;
- tree tags;
- tree args;
- int superblock_address;
- {
- register tree decl;
- register int i;
- register int *addr_buffer;
- struct block buffer;
- int n_decls, n_tags, n_args, total;
- register struct blockvec_elt *velt;
- int block_address;
-
- for (decl = decls, i = 0; decl; decl = TREE_CHAIN (decl))
- if (! TREE_EXTERNAL (decl)
- || TREE_CODE (TREE_TYPE (decl)) != FUNCTION_TYPE)
- i++;
-
- n_decls = i;
-
- for (decl = args, i = 0; decl; decl = TREE_CHAIN (decl), i++);
- n_args = i;
-
- for (decl = tags, i = 0; decl; decl = TREE_CHAIN (decl), i++);
- n_tags = i;
-
- total = n_decls + n_args + n_tags;
-
- addr_buffer = (int *) alloca (total * sizeof (int));
-
- symout_block_symbols (args, addr_buffer, 0);
- symout_block_symbols (decls, addr_buffer + n_args, 0);
- symout_block_tags (tags, addr_buffer + n_decls + n_args);
-
- velt = (struct blockvec_elt *) xmalloc (sizeof (struct blockvec_elt));
- velt->next = blockvec;
- velt->address = next_address;
- blockvec = velt;
-
- buffer.startaddr = 0;
- buffer.endaddr = 0;
- buffer.superblock = (struct block *) superblock_address;
- buffer.function = 0;
- buffer.nsyms = total;
-
- block_address = next_address;
- fwrite (&buffer, sizeof buffer - sizeof buffer.sym, 1, symfile);
- next_address += sizeof buffer - sizeof buffer.sym;
-
- fwrite (addr_buffer, sizeof (int), total, symfile);
- next_address += total * sizeof (int);
-
- fprintf (asmfile, "\t.gdbblock %d,%d\n", total_blocks + 2, block_address);
- total_blocks++;
-
- return block_address;
- }
-
- /* Walk STMT, the body of a function, and output symtab data on
- all the blocks that compose it and all symbols inside them.
- ARGS is a chain of decls for argument variables of the function.
- SUPERBLOCK_ADDRESS is the address of symbol data for the
- innermost block containing STMT; it is used for recursive calls,
- and is always 0 for the outermost call (since the containing
- block for a function is output later than the function). */
-
- int
- symout_function (stmt, args, superblock_address)
- register tree stmt;
- tree args;
- int superblock_address;
- {
- int address = superblock_address;
-
- while (stmt)
- {
- switch (TREE_CODE (stmt))
- {
- case COMPOUND_STMT:
- case LOOP_STMT:
- symout_function (STMT_BODY (stmt), 0, address);
- break;
-
- case IF_STMT:
- symout_function (STMT_THEN (stmt), 0, address);
- symout_function (STMT_ELSE (stmt), 0, address);
- break;
-
- case LET_STMT:
- /* Ignore LET_STMTs for blocks never really used to make RTL. */
- if (! TREE_USED (stmt))
- break;
- address =
- symout_block (STMT_VARS (stmt), STMT_TYPE_TAGS (stmt), args,
- superblock_address);
-
- symout_function (STMT_SUBBLOCKS (stmt), 0, address);
- }
- stmt = TREE_CHAIN (stmt);
- }
- return address;
- }
-
- symout_function_end ()
- {
- /* Output dummy entries for any undefined structure references. */
- symout_types (filter_undefined_types (temporary_fwd_refs));
- temporary_fwd_refs = 0;
- }
-
- /* Output all the data structure for a top two blocks in a compilation.
- The top block is for public (global) symbols;
- the next one is for private (this file only) symbols.
-
- DECLS is the chain of declarations of variables in this block.
- TAGS is the list of struct, union and enum tag definitions. */
-
- void
- symout_top_blocks (decls, tags)
- tree decls;
- tree tags;
- {
- register tree decl;
- register int i;
- register int *addr_buffer;
- struct block buffer;
- int n_decls, n_tags;
- register struct blockvec_elt *velt;
- int top_block_addr;
-
- /* First do the public-symbols block. */
-
- for (decl = decls, i = 0; decl; decl = TREE_CHAIN (decl))
- if (TREE_PUBLIC (decl) && ! TREE_EXTERNAL (decl))
- i++;
- n_decls = i;
-
- addr_buffer = (int *) alloca (n_decls * sizeof (int));
-
- symout_block_symbols (decls, addr_buffer, 2);
-
- fprintf (asmfile, ".text 0\n\t.gdbend 0\n");
- fprintf (asmfile, "\t.gdbblock 0,%d\n", next_address);
-
- total_blocks++;
- velt = (struct blockvec_elt *) xmalloc (sizeof (struct blockvec_elt));
- velt->next = blockvec;
- velt->address = next_address;
- blockvec = velt;
-
- top_block_addr = next_address;
-
- buffer.startaddr = 0;
- buffer.endaddr = 0;
- buffer.superblock = 0;
- buffer.function = 0;
- buffer.nsyms = n_decls;;
-
- fwrite (&buffer, sizeof buffer - sizeof buffer.sym, 1, symfile);
- next_address += sizeof buffer - sizeof buffer.sym;
-
- fwrite (addr_buffer, sizeof (int), n_decls, symfile);
- next_address += n_decls * sizeof (int);
-
- /* Next do the private-symbols block. */
-
- for (decl = decls, i = 0; decl; decl = TREE_CHAIN (decl))
- if (! TREE_PUBLIC (decl) && ! TREE_EXTERNAL (decl))
- i++;
- n_decls = i;
-
- for (decl = tags, i = 0; decl; decl = TREE_CHAIN (decl), i++);
- n_tags = i;
-
- addr_buffer = (int *) alloca ((n_decls + n_tags) * sizeof (int));
-
- symout_block_symbols (decls, addr_buffer, 1);
- symout_block_tags (tags, addr_buffer + n_decls);
-
- fprintf (asmfile, "\t.gdbend 1\n");
- fprintf (asmfile, "\t.gdbblock 1,%d\n", next_address);
-
- total_blocks++;
- velt = (struct blockvec_elt *) xmalloc (sizeof (struct blockvec_elt));
- velt->next = blockvec;
- velt->address = next_address;
- blockvec = velt;
-
- buffer.startaddr = 0;
- buffer.endaddr = 0;
- buffer.superblock = (struct block *) top_block_addr;
- buffer.function = 0;
- buffer.nsyms = n_decls + n_tags;;
-
- fwrite (&buffer, sizeof buffer - sizeof buffer.sym, 1, symfile);
- next_address += sizeof buffer - sizeof buffer.sym;
-
- fwrite (addr_buffer, sizeof (int), n_decls + n_tags, symfile);
- next_address += (n_decls + n_tags) * sizeof (int);
- }
-
- /* Output the source-line-number information. */
-
- /* Output a `struct source' for the source file described by F.
- Return the address-in-the-symseg of the `struct source'. */
-
- static int
- symout_source_file (f)
- struct gdbfile *f;
- {
- /* Make the `struct source' big enough for as many lines as
- this file has. */
- int size = sizeof (struct source) + (f->nlines - 1) * sizeof (struct line);
- struct source *buffer
- = (struct source *) alloca (size);
- int addr;
-
- /* Use zero for the line data, since assembler will store the real data. */
- bzero (buffer, size);
-
- /* Output the file's name as a string. The assembler doesn't know this. */
- buffer->name = (char *) next_address;
- symout_strings (f->name, 0, 0, 0);
- buffer->nlines = f->nlines;
-
- /* Write the structure. */
- addr = next_address;
- fwrite (buffer, 1, size, symfile);
- next_address += size;
-
- /* Tell assembler where to write the real line-number data. */
- fprintf (asmfile, "\t.gdblinetab %d,%d\n",
- f->filenum, addr + sizeof (int));
-
- return addr;
- }
-
- /* Output the `struct sourcevector' which describes all the
- source files and points a `struct source' for each one. */
-
- static int
- symout_sources ()
- {
- register struct gdbfile *f;
- int nfiles = 0;
- struct sourcevector *s;
- int i;
- int size;
- int addr;
-
- /* Count number of files to determine size of the sourcevector. */
- for (f = gdbfiles; f; f = f->next)
- ++nfiles;
-
- /* Allocate buffer for the sourcevector and record its length. */
- size = sizeof (int) + nfiles * sizeof (struct source *);
- s = (struct sourcevector *) alloca (size);
- s->length = nfiles;
-
- /* Output a `struct source' for each file; put address into sourcevector. */
- for (f = gdbfiles, i = 0; f; f = f->next, i++)
- s->source[i] = (struct source *) symout_source_file (f);
-
- /* Output the sourcevector. */
- addr = next_address;
- fwrite (s, 1, size, symfile);
- next_address += size;
- return addr;
- }
-
- /* Call here at the end of compilation, after outputting all the
- blocks and symbols, to output the blockvector and typevector
- and close the symbol table file. FILETIME is source file's
- creation time. */
-
- void
- symout_finish (filename, filetime)
- char *filename;
- int filetime;
- {
- int *blockvector = (int *) alloca ((total_blocks + 1) * sizeof (int));
- int *typevector;
- int now = time (0);
- register int i;
- struct symbol_root buffer;
- char dir[MAXNAMLEN];
-
- /* Output dummy entries for any undefined structure references. */
- symout_types (filter_undefined_types (permanent_fwd_refs));
-
- typevector = (int *) alloca ((total_types + 1) * sizeof (int));
-
- buffer.language = language_c;
- buffer.blockvector = (struct blockvector *) next_address;
-
- /* The two blocks at the beginning of the chain
- are the file's private symbols block and public symbols block.
- They belong at the front of the blockvector, in that order. */
- blockvector[2] = blockvec->address;
- blockvec = blockvec->next;
- blockvector[1] = blockvec->address;
- blockvec = blockvec->next;
-
- /* The rest of the blocks are in the chain in reverse order. */
- for (i = total_blocks; i > 2; i--)
- {
- blockvector[i] = blockvec->address;
- blockvec = blockvec->next;
- }
- blockvector[0] = total_blocks;
-
- fwrite (blockvector, sizeof (int), total_blocks + 1, symfile);
- next_address += sizeof (int) * (total_blocks + 1);
-
- buffer.typevector = (struct typevector *) next_address;
-
- for (i = total_types; i > 0; i--)
- {
- typevector[i] = typevec->address;
- typevec = typevec->next;
- }
- typevector[0] = total_types;
-
- fwrite (typevector, sizeof (int), total_types + 1, symfile);
- next_address += sizeof (int) * (total_types + 1);
-
- buffer.sourcevector = (struct sourcevector *) symout_sources ();
-
- buffer.format = 1;
- buffer.textrel = 0; /* These four will be set up by linker. */
- buffer.datarel = 0; /* Make them 0 now, which is right for */
- buffer.bssrel = 0; /* looking at the .o file in gdb. */
- buffer.ldsymoff = 0;
-
- buffer.version = (char *) next_address;
- symout_strings (ctime (&filetime), 0, 0, 0);
-
- buffer.compilation = (char *) next_address;
- symout_strings (ctime (&now), 0, 0, 0);
-
- buffer.filename = (char *) next_address;
- symout_strings (filename, 0, 0, 0);
-
- buffer.filedir = (char *) next_address;
- #ifdef USG
- strcpy (dir, getcwd (dir, MAXNAMLEN));
- #else
- #ifndef VMS
- getwd (dir);
- #else
- abort ();
- #endif
- #endif
- symout_strings (dir, 0, 0, 0);
-
- fflush (symfile);
-
- if (ferror (symfile) != 0)
- fatal_io_error (symfile_name);
-
- buffer.length = next_address;
-
- if (lseek (fileno (symfile), 0, 0) < 0)
- pfatal_with_name (symfile_name);
- if (write (fileno (symfile), &buffer, sizeof buffer) < 0)
- pfatal_with_name (symfile_name);
- close (fileno (symfile));
- }
-